#ifndef HANDLEVIRTUAL_HPP
#define HANDLEVIRTUAL_HPP

#include <stdio.h>
#include <cassert>
#include <string>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <sstream>
#include "json11/json11.hpp"
#include <list>
#include <set>
#include <unordered_map>
#include <algorithm>
#include <type_traits>
#include <fstream>
#include "sys/io.h"
#include <unistd.h>

using namespace std;
using namespace json11;
#include <opencv2/opencv.hpp>
using namespace cv;

typedef struct _Point{
    double x;
    double y;
}Struc_Point;//虚拟墙坐标点

int virtualWrite(Json t1, string file_path) {

	string sspace = "			";
	string ssspace = "				";
	string sssspace = "					";
	Json::array t_total;
    Json::array t1_arr = t1["map_walls"].array_items();
	if (access(file_path.c_str(), 0) != 0) {
		//creat new task.json
		ofstream out_file(file_path.c_str());
		if(!out_file.is_open()){
			cout << "failed to open task.json" << endl;
			return -1;
		}
		out_file.close();
	}
	else {

		ifstream in_file(file_path.c_str());
		if(!in_file.is_open()){
			cout << "failed to open task.json" << endl;
			return -1;
		}
		stringstream buffer;
		string err;
		buffer << in_file.rdbuf();
		//cout << "parse result: " << buffer.str() << endl;
		Json test_tmp = Json::parse(buffer.str(), err);
		t_total = test_tmp["map_walls"].array_items();
		// cout << test_tmp.dump() << endl;
		in_file.close();
	}
	int t1_size = t1_arr.size();

    for(int j=0;j<t1_size;j++){
        Json::array wall_json = t1_arr[j]["wall_points"].array_items();
        Json::array area_json = t1_arr[j]["area_points"].array_items();
        if(wall_json.size()){
            Json wallJson = Json::object{{"wall_points",t1_arr[j]["wall_points"]}};
            cout<<wallJson.dump()<<endl;
            t_total.push_back(wallJson);
        }
        if(area_json.size()){
            Json wallJson = Json::object{{"area_points",t1_arr[j]["area_points"]}};
            cout<<wallJson.dump()<<endl;
            t_total.push_back(wallJson);
        }
        
    }

    int newJson_size = t_total.size();
	ofstream inputJson(file_path.c_str(), ios::trunc);
	if(!inputJson.is_open()){
		cout << "failed to open task.json" << endl;
		return -1;
	}
	
	// write json
	inputJson << "{" << endl;
    inputJson << "	" << "\"map_walls\": [" << endl;

	for (int i = 0; i < newJson_size; i++) {
        Json::array temp_path = t_total[i]["wall_points"].array_items();
		int t_num = temp_path.size();
        if(t_num){   
            inputJson << "		" << "{" << endl;
            inputJson << sspace << "\"wall_points\"" << ": " << "[" << endl;
            
            for (int j = 0; j < t_num; j++) {
                
                inputJson << ssspace << "{" << endl;
                inputJson << sssspace << "\"x\"" << ": " << t_total[i]["wall_points"][j]["x"].number_value() << "," << endl;
                inputJson << sssspace << "\"y\"" << ": "  << t_total[i]["wall_points"][j]["y"].number_value() << endl;
                inputJson << ssspace << "}" ;
                
                if (j < (t_num - 1)) {
                    inputJson << "," << endl;
                }

            }
            inputJson << "]" << endl;    
        }
        Json::array area = t_total[i]["area_points"].array_items();
		int a_num = area.size();
        if(a_num){   
            inputJson << "		" << "{" << endl;
            inputJson << sspace << "\"area_points\"" << ": " << "[" << endl;
            
            for (int j = 0; j < a_num; j++) {
                
                inputJson << ssspace << "{" << endl;
                inputJson << sssspace << "\"x\"" << ": " << t_total[i]["area_points"][j]["x"].number_value() << "," << endl;
                inputJson << sssspace << "\"y\"" << ": "  << t_total[i]["area_points"][j]["y"].number_value() << endl;
                inputJson << ssspace << "}" ;
                
                if (j < (a_num - 1)) {
                    inputJson << "," << endl;
                }

            }
            inputJson << "]" << endl;    
        }
        inputJson << "		" << "}";
		if (i < (newJson_size - 1)) {
			inputJson << "," << endl;
		}
	}
	inputJson << "	" << "]" << endl;
	inputJson << "}";

	inputJson.close();
	return 0;
}

int virtualDelete(Json t1, string file_path) {

	string sspace = "			";
	string ssspace = "				";
	string sssspace = "					";
	Json::array t_total;
	Json::array t1_arr = t1["map_walls"].array_items();
	if (access(file_path.c_str(), 0) != 0) {
		//creat new task.json
		ofstream out_file(file_path.c_str());
		if(!out_file.is_open()){
			cout << "failed to open task.json" << endl;
			return -1;
		}
		out_file.close();
	}
	else {

		ifstream in_file(file_path.c_str());
		if(!in_file.is_open()){
			cout << "failed to open task.json" << endl;
			return -1;
		}
		stringstream buffer;
		string err;
		buffer << in_file.rdbuf();
		//cout << "parse result: " << buffer.str() << endl;
		Json test_tmp = Json::parse(buffer.str(), err);
		t_total = test_tmp["map_walls"].array_items();
		// cout << test_tmp.dump() << endl;
		in_file.close();
	}
	
	Json::array newJson;
	Json::array wall_points;
	Json::array area_points;
	Json::array t1_wall_points;
	Json::array t1_area_points;
	
	int t1_size = t1_arr.size();
	for(int i = 0;i < t_total.size();i++){
		wall_points = t_total[i]["wall_points"].array_items();
		int wall_points_size = wall_points.size();

		area_points = t_total[i]["area_points"].array_items();
		int area_points_size = area_points.size();

		if(wall_points_size){
			for(int j=0;j<t1_size;j++){
				t1_wall_points = t1_arr[j]["wall_points"].array_items();
				int t1_wall_points_size = t1_wall_points.size();
				if(t1_wall_points_size!=0	&&
					wall_points[0]["x"].number_value()==t1_wall_points[0]["x"].number_value() &&
					wall_points[0]["y"].number_value()==t1_wall_points[0]["y"].number_value()){
						continue;
				}
				Json wallJson = Json::object{{"wall_points",wall_points}};
				newJson.push_back(wallJson);
			}
			
		}
		if(area_points_size){
			for(int j=0;j<t1_size;j++){
				t1_area_points = t1_arr[j]["area_points"].array_items();
				int t1_area_points_size = t1_area_points.size();
				if(t1_area_points_size!=0	&&
					area_points[0]["x"].number_value()==t1_area_points[0]["x"].number_value() &&
					area_points[0]["y"].number_value()==t1_area_points[0]["y"].number_value()){
						continue;
				}
				Json areaJson = Json::object{{"area_points",area_points}};
				newJson.push_back(areaJson);
			}
		}
		
	}

	// t_total.push_back(t1);
	ofstream inputJson(file_path.c_str(), ios::trunc);
	if(!inputJson.is_open()){
		cout << "failed to open task.json" << endl;
		return -1;
	}
	
	// write json
	inputJson << "{" << endl;
    inputJson << "	" << "\"map_walls\": [" << endl;

	int wall_num = newJson.size();
	for (int i = 0; i < wall_num; i++) {
        Json::array temp_path = t_total[i]["wall_points"].array_items();
		int t_num = temp_path.size();
        if(t_num){   
            inputJson << "		" << "{" << endl;
            inputJson << sspace << "\"wall_points\"" << ": " << "[" << endl;
            
            for (int j = 0; j < t_num; j++) {
                
                inputJson << ssspace << "{" << endl;
                inputJson << sssspace << "\"x\"" << ": " << t_total[i]["wall_points"][j]["x"].number_value() << "," << endl;
                inputJson << sssspace << "\"y\"" << ": "  << t_total[i]["wall_points"][j]["y"].number_value() << endl;
                inputJson << ssspace << "}" ;
                
                if (j < (t_num - 1)) {
                    inputJson << "," << endl;
                }

            }
            inputJson << "]" << endl;    
        }
        Json::array area = t_total[i]["area_points"].array_items();
		int a_num = area.size();
        if(a_num){   
            inputJson << "		" << "{" << endl;
            inputJson << sspace << "\"area_points\"" << ": " << "[" << endl;
            
            for (int j = 0; j < a_num; j++) {
                
                inputJson << ssspace << "{" << endl;
                inputJson << sssspace << "\"x\"" << ": " << t_total[i]["area_points"][j]["x"].number_value() << "," << endl;
                inputJson << sssspace << "\"y\"" << ": "  << t_total[i]["area_points"][j]["y"].number_value() << endl;
                inputJson << ssspace << "}" ;
                
                if (j < (a_num - 1)) {
                    inputJson << "," << endl;
                }

            }
            inputJson << "]" << endl;    
        }
        inputJson << "		" << "}";
		if (i < (wall_num - 1)) {
			inputJson << "," << endl;
		}
	}
	inputJson << "	" << "]" << endl;
	inputJson << "}";

	inputJson.close();
	cout<<"virtualDelete successful!"<<endl;
	return 0;
}

int virtualDeleteWall(string file_path) {

	string sspace = "			";
	string ssspace = "				";
	string sssspace = "					";
	Json::array t_total;
	if (access(file_path.c_str(), 0) != 0) {
		//creat new task.json
		ofstream out_file(file_path.c_str());
		if(!out_file.is_open()){
			cout << "failed to open task.json" << endl;
			return -1;
		}
		out_file.close();
	}
	else {

		ifstream in_file(file_path.c_str());
		if(!in_file.is_open()){
			cout << "failed to open task.json" << endl;
			return -1;
		}
		stringstream buffer;
		string err;
		buffer << in_file.rdbuf();
		//cout << "parse result: " << buffer.str() << endl;
		Json test_tmp = Json::parse(buffer.str(), err);
		t_total = test_tmp["map_walls"].array_items();
		// cout << test_tmp.dump() << endl;
		in_file.close();
	}
	ofstream inputJson(file_path.c_str(), ios::trunc);
	if(!inputJson.is_open()){
		cout << "failed to open task.json" << endl;
		return -1;
	}

	int p_num = t_total.size();
    int count = 0;
    for(int i = 0;i<p_num;i++){
        Json::array temp_path = t_total[i]["wall_points"].array_items();
		int t_num = temp_path.size();
        if(t_num){
            count++;
        }
    }
	// write json
	inputJson << "{" << endl;
    inputJson << "	" << "\"map_walls\": [" << endl;

	for (int i = 0; i < count; i++) {
        Json::array area = t_total[i]["area_points"].array_items();
		int a_num = area.size();
        if(a_num){   
            inputJson << "		" << "{" << endl;
            inputJson << sspace << "\"area_points\"" << ": " << "[" << endl;
            
            for (int j = 0; j < a_num; j++) {
                
                inputJson << ssspace << "{" << endl;
                inputJson << sssspace << "\"x\"" << ": " << t_total[i]["area_points"][j]["x"].number_value() << "," << endl;
                inputJson << sssspace << "\"y\"" << ": "  << t_total[i]["area_points"][j]["y"].number_value() << endl;
                inputJson << ssspace << "}" ;
                
                if (j < (a_num - 1)) {
                    inputJson << "," << endl;
                }

            }
            inputJson << "]" << endl;    
        }
        inputJson << "		" << "}";
		if (i < (count - 1)) {
			inputJson << "," << endl;
		}
	}
	inputJson << "	" << "]" << endl;
	inputJson << "}";

	inputJson.close();
	cout<<"virtualDeleteWall successful!"<<endl;
	return 0;
}

int virtualDeleteArea(string file_path) {

	string sspace = "			";
	string ssspace = "				";
	string sssspace = "					";
	Json::array t_total;
	if (access(file_path.c_str(), 0) != 0) {
		//creat new task.json
		ofstream out_file(file_path.c_str());
		if(!out_file.is_open()){
			cout << "failed to open task.json" << endl;
			return -1;
		}
		out_file.close();
	}
	else {

		ifstream in_file(file_path.c_str());
		if(!in_file.is_open()){
			cout << "failed to open task.json" << endl;
			return -1;
		}
		stringstream buffer;
		string err;
		buffer << in_file.rdbuf();
		//cout << "parse result: " << buffer.str() << endl;
		Json test_tmp = Json::parse(buffer.str(), err);
		t_total = test_tmp["map_walls"].array_items();
		// cout << test_tmp.dump() << endl;
		in_file.close();
	}
	ofstream inputJson(file_path.c_str(), ios::trunc);
	if(!inputJson.is_open()){
		cout << "failed to open task.json" << endl;
		return -1;
	}
    int p_num = t_total.size();
    int count = 0;
    for(int i = 0;i<p_num;i++){
        Json::array temp_path = t_total[i]["wall_points"].array_items();
		int t_num = temp_path.size();
        if(t_num){
            count++;
        }
    }
	// write json
	inputJson << "{" << endl;
    inputJson << "	" << "\"map_walls\": [" << endl;

	for (int i = 0; i < count; i++) {
        Json::array temp_path = t_total[i]["wall_points"].array_items();
		int t_num = temp_path.size();
        if(t_num){   
            inputJson << "		" << "{" << endl;
            inputJson << sspace << "\"wall_points\"" << ": " << "[" << endl;
            
            for (int j = 0; j < t_num; j++) {
                
                inputJson << ssspace << "{" << endl;
                inputJson << sssspace << "\"x\"" << ": " << t_total[i]["wall_points"][j]["x"].number_value() << "," << endl;
                inputJson << sssspace << "\"y\"" << ": "  << t_total[i]["wall_points"][j]["y"].number_value() << endl;
                inputJson << ssspace << "}" ;
                
                if (j < (t_num - 1)) {
                    inputJson << "," << endl;
                }

            }
            inputJson << "]" << endl;    
        }
        inputJson << "		" << "}";
		if (i < (count - 1)) {
			inputJson << "," << endl;
		}
	}
	inputJson << "	" << "]" << endl;
	inputJson << "}";

	inputJson.close();
	cout<<"virtualDeleteArea successful!"<<endl;
	return 0;
}

int  line_virtual(string path,string json_path,string save_png_path){
    Mat in_img;
    in_img = cv::imread(path,0);
    if(in_img.empty()){

        cout << "err!!! input image cannot be read..\n";
        return 1;
    }
    Json virtualwall = ReadJson(json_path);
	
    Json::array array_row = virtualwall["map_walls"].array_items();
	int size = array_row.size();
    if(size == 0)return 1;

    int i=0,j=0;
	Json::array tmp;
    for(i = 0; i < array_row.size(); i++){
		int  a= array_row[i]["wall_points"].array_items().size();
		if(a){
            ROS_INFO("wall_points!");
        	tmp = array_row[i]["wall_points"].array_items();
		}
		int  b= array_row[i]["area_points"].array_items().size();
		if(b){
            ROS_INFO("area_points!");
			tmp = array_row[i]["area_points"].array_items();
		}

        int point_number = tmp.size(); 
        cout << "point_number of lines is " << point_number << endl;
        Struc_Point point[point_number]; 

        for(j = 0;j<point_number;j++){
            // cout<<tmp[i]["x"].number_value()<<"    "<<tmp[i]["y"].number_value()<<endl;
            point[j].x = tmp[j]["x"].number_value();
            point[j].y = tmp[j]["y"].number_value();
            if(j>0){
                printf("point:(%lf,%lf),(%lf,%lf)\n", point[j-1].x, point[j-1].y, point[j].x, point[j].y);
                line(in_img,Point(point[j-1].x,point[j-1].y),Point(point[j].x,point[j].y),Scalar(0,0,255),1);
            }
        }
		
    }
    imwrite(save_png_path,in_img);
	return 0;
}
#endif